// demo.c
//
// demo program for MTE 241
// demonstrates	use of signals and setting up shared memory
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*  modified June 5, 2007 by P. Dasiewicz
    modified May 6, 2009 by P. Dasiewicz

	The example was modified to remove the traditional UNIX approach of using
	shared memory get/attach since this was suddenly causing problems on eceunix.
	
	It has been modified to use the POSIX-style using functions mmap etc. to
	defined a memory mapped file which can then be used as a shared memory
	segment (between multiple processes) and accessed by standard C-type pointers.
	Basically, behaves exactly the same as the traditional UNIX shared memory.
	
	
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
 #include <stdlib.h>
#include <signal.h>
#include <unistd.h>			// getpid() definition
#include <fcntl.h>

#include <sys/mman.h>
#include <sys/wait.h>
#include <stdio.h>
 */

//#include "global.h"
#include "kernel.h"
//for send_console_char and i_proc communication
//MsgEnvQ * Display_Q= new MsgEnvQ;


// globals
inputbuf  * in_mem_p, * out_mem_p;		// pointer to structure that is the shared memory
int 	in_pid, out_pid;				// pid of keyboard child process
void * mmap_ptr1, *mmap_ptr2;
int bufsize = BUFFERSIZE;
int fid1, fid2, status;		//used to create the shared memory


//RTX * rtx=new RTX();         
RTX rtx;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
char * sfilename1 = "kbc_share_mem";  //the name of the shared_memory file
char * sfilename2 = "crt_share_mem";
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void kbd_handler(int signum){
    rtx.atomic(ON);
    if (signum==SIGUSR1)
    {
        rtx.prev_proc=rtx.cur_proc;
        rtx.cur_proc=rtx.get_PCB(KB);
        //rtx.cur_proc=rtx.get_PCB(KB);
        //rtx.context_switch(rtx.prev_proc,rtx.cur_proc);
        kbd_iproc();
        return;
    }
    else 
        in_mem_p->ok_flag = 0;
    rtx.atomic(OFF);
    return;
}

void kbd_iproc()
{	  
    printf("signal from kbd is received by kbd_iproc\n");
    // copy input buffer
    //while(1)
    //{                      
         printf("kb_iproc trying to receive msg\n");
         MsgEnv * msgenv=rtx.receive_message();              
         printf("kb_iproc received msg\n");
         //int senderpid=msgenv->sender_pid;
         //PCB * sender=rtx.get_PCB(senderpid);
         //newMsgEnv->msg_data=
         strcpy(msgenv->msg_data,in_mem_p->indata); 
         //strcat(msgenv->msg_data,'\n');
         //printf("msg from kb_iproc wrote\n");
         //rtx->send_message(sender,msgenv);
         msgenv->type=console_input;
         // printf("keb input is %s \n:", newMsgEnv->msg_data);
	     // we should parse the input string and execute the command given,
	     //  but for now we just echo the input
	     // 
	     //  strcpy(command.indata,in_mem_p->indata);
	     // printf("Keyboard input was: %s\n",command.indata);
	     //in_mem_p->ok_flag = 0;  // tell child that the buffer has been emptied
	     //kill(out_pid,SIGUSR2);
	 in_mem_p->ok_flag = 0;  // tell child that the buffer has been emptied
         rtx.send_message(msgenv->sender_pid, msgenv);
         printf("KB iproc sent message to [%d]\n",msgenv->sender_pid);
            // sender->msgQ->enqueue(msgenv);
         rtx.cur_proc=rtx.prev_proc;
         rtx.prev_proc=rtx.get_PCB(KB);
         printf("KB iproc change cur_proc from [%d] to [%d]\n",KB,rtx.cur_proc->pid);
         //rtx.context_switch(rtx.prev_proc,rtx.cur_proc);
         
	     
    //}
    return;
}

void crt_handler(int signum){
    //rtx.atomic(ON);
    //rtx.cur_proc=rtx.get_PCB(CRT);  
    //rtx.prev_proc=rtx.cur_proc;
    //rtx.cur_proc=rtx.get_PCB(CRT);
    if(signum==SIGUSR2)//when CRT sends signal
    {
        rtx.prev_proc=rtx.cur_proc;
        rtx.cur_proc=rtx.get_PCB(CRT);
        crt_iproc();
        //rtx.context_switch(rtx.prev_proc,rtx.cur_proc);        
        //crt_iproc();
    }
    else{//when send_console_char 
         printf("crt_handler called by send_console_char1\n"); 
         MsgEnv * msgenv;
        while(out_mem_p->ok_flag==0){};
        printf("crt received msg and trying to write to shared mem\n");     
        //MsgEnv * msgenv=rtx.receive_message();
        //rtx.Display_Q->dequeue(msgenv)
        msgenv=rtx.Display_Q->head;
        if(msgenv!=NULL){
        strcpy(out_mem_p->indata,msgenv->msg_data);
        
       // printf("\n\n\n\n\nmsg to be displayed is %s\n\n\n\n\n\n",out_mem_p->indata); 
        }
        //Display_Q->enqueue(msgenv);
        //rtx.cur_proc=rtx.prev_proc;
        //strcpy(out_mem_p->indata,message_envolope->msg_data);
    }
    
    //MsgEnv * msgenv=rtx.receive_message();	
    //strcpy(out_mem_p->indata,msgenv->msg_data);
    //rtx.cur_proc=rtx.prev_proc; 
    //rtx.atomic(OFF);
        return;
}
     
void crt_iproc()
{	
    MsgEnv * msgenv;
    int senderpid;
    //while(1){
        printf("crt_iproc is running1\n"); 
        printf("in crt cur_proc is [%d]\n",rtx.cur_proc->pid);
        //msgenv=rtx.receive_message();	
        if(rtx.Display_Q->getsize()>0){
            msgenv=rtx.Display_Q->dequeue();
            if(msgenv!=NULL){
            printf("crt_iproc is running2\n"); 

            senderpid=msgenv->sender_pid;
             printf("in crt before send display_ack ,msg has target [%d] and sender [%d]\n",msgenv->target_pid,msgenv->sender_pid);
                    msgenv->type=display_ack;
      //  printf("crt_iproc is running4\n"); 
        rtx.send_message(senderpid, msgenv);
            printf("crt_iproc is running3\n"); 
            }
        }
        
        //PCB * sender=rtx.get_PCB(senderpid);
	// copy input buffer
//	if (msgenv->msg_data[0] != '\0')
//	{
    //strcpy(out_mem_p->indata,msgenv->msg_data); 
        //msgenv->type=display_ack;
        printf("crt_iproc is running4\n"); 
       // rtx.send_message(senderpid, msgenv);        
        printf("CRT sends display_ack to [%d]!!!!!\n",senderpid);
    //sender->msgQ->enqueue(msgenv);
	    // we should parse the input string and execute the command given,
	    //  but for now we just echo the input
	    // 
	    //printf("%s\n",out_mem_p->indata);
	    //out_mem_p->ok_flag = 0;  // tell child that the buffer has been emptied
        rtx.cur_proc=rtx.prev_proc;
        rtx.prev_proc=rtx.get_PCB(CRT);
        printf("CRT iproc change cur_proc from [%d] to [%d]\n",CRT,rtx.cur_proc->pid);
        //setcontext(&(rtx.cur_proc->proContext));
        //rtx.context_switch(rtx.prev_proc,rtx.cur_proc);
	    //return;
     //}
//	}
     return;
 //   else
 //   printf("only enter is entered???\n");
 //   in_mem_p->ok_flag = 0;
}

//void timeout_list(){

void timer_handler(int signum){
    //rtx.cur_proc=rtx.get_PCB(Timer);
    //timer_iproc();
    //if (signum==SIGALRM)
    //{
    rtx.atomic(ON);
        rtx.prev_proc=rtx.cur_proc;
        rtx.cur_proc=rtx.get_PCB(Timer);
        //rtx.cur_proc=rtx.get_PCB(KB);
        //rtx.context_switch(rtx.prev_proc,rtx.cur_proc);
        timer_iproc();
        rtx.atomic(OFF);
        return;
   // }
    //else{
        
    //}
   // return;
    
}

void timer_iproc(){
    //printf("timer iproc is running for the first time\n"); 
    //while(1)
    //{ 
        //printf("timer iproc is running \n");
        rtx.clock_increment();
         MsgEnv* temp,*temp1,*temp2;
          ///printf("timer iproc trying to receive msg, it has [%d] messages\n",rtx.cur_proc->msgQ->getsize()); 
          while(rtx.cur_proc->msgQ->getsize()!=0){
              temp=rtx.receive_message();
              if(temp!=NULL){
                  printf("sender id ->[%d]\n",temp->sender_pid);
                rtx.timeoutq_enqueue(temp);
              }
          }

         //rtx.timeout_list->timeoutq_enqueue(temp);


        if (rtx.get_timeoutq_head()!=NULL){
           
           temp1=rtx.get_timeoutq_head(); 
           printf("temp1 head's sender is [%d], with ticks=[%d]\n",rtx.get_timeoutq_head()->sender_pid,rtx.get_timeoutq_head()->num_clock_ticks);
            while(temp1!=NULL){
                //printf("temp1 head's sender is [%d]\n",rtx.get_timeoutq_head()->sender_pid);
                temp1->num_clock_ticks--;
                temp1=temp1->next;
            }
            //code to decrement the tick count of 1st in the timeout_list
           while((rtx.get_timeoutq_tail()!=NULL) && (rtx.get_timeoutq_tail()->num_clock_ticks==0)){
                    printf("dequeue from timeout queue\n");
                     printf("size of timeout queue is [%d]\n",rtx.timeout_list->size);
                     printf("cur proc is [%d]\n",rtx.cur_proc->pid);
                    temp2=rtx.timeoutq_dequeue();
                    if(temp2==NULL){printf("time out queue return NULL\n");}
                     printf("times up! return msg to [%d]\n",temp2->sender_pid);                     
                    rtx.send_message(temp2->sender_pid, temp2); //returns envelope
              
                 //   printf("TIMER send wake up code back to the process!!!!!!!!!!!!!!!!!!!!!\n");
            }
        }
         rtx.cur_proc=rtx.prev_proc;
         rtx.prev_proc=rtx.get_PCB(Timer);
         //printf("Timer iproc call context switch from [%d] to [%d]\n",Timer,rtx.cur_proc->pid);
         //rtx.context_switch(rtx.prev_proc,rtx.cur_proc);
         return;
    //}
} 




void cleanup()
{
	
	// terminate child process(es)
	kill(in_pid,SIGINT);
    kill(out_pid,SIGINT);
	// remove shared memory segment and do some standard error checks
	status = munmap(mmap_ptr1, bufsize);
    if (status == -1){
      printf("Bad munmap during cleanup\n");
    }
	// close the temporary mmap file 
    status = close(fid1); 
    if (status == -1){
      printf("Bad close of temporary mmap file during cleanup\n");
    };
	// unlink (i.e. delete) the temporary mmap file
    status = unlink(sfilename1); 
    if (status == -1){
      printf("Bad unlink during claeanup.\n");
    }
    
   	status = munmap(mmap_ptr2, bufsize);
    if (status == -1){
      printf("Bad munmap during cleanup\n");
    }
	// close the temporary mmap file 
    status = close(fid2); 
    if (status == -1){
      printf("Bad close of temporary mmap file during cleanup\n");
    };
	// unlink (i.e. delete) the temporary mmap file
    status = unlink(sfilename2); 
    if (status == -1){
      printf("Bad unlink during claeanup.\n");
    }
}


//**************************************************************************
// routine to call before exitting
// This routine gets called when certain signals occur

void die(int signal)
{
	cleanup();
	printf("\nSignal received is %i",signal);
	printf( "\n\nSignal Received.   Leaving demo ...\n" );
	exit(0);
}
//**************************************************************************
// routine to clean up things before terminating main program
// This stuff must be cleaned up or we have child processes and shared
//	memory hanging around after the main process terminates



void Process_A(){
     //printf("proc A running\n");
     MsgEnv* envelope=rtx.receive_message();
     printf("proc A [%d] received msg envelope\n",ProcessA);
     int filler=rtx.release_msg_env(envelope);     
     int num=0;
     while(1){
         envelope=rtx.request_msg_env();
         envelope->type=count_report;
         envelope->msg_data[1]=num;
         printf("proc A [%d] sends msg envelope to B [%d]\n",ProcessA,ProcessB);
         rtx.send_message(ProcessB, envelope );          
         num++;
         printf("proc A [%d] released processor, and it's enqueued to ready queue\n",ProcessA);
         rtx.release_processor( );
     }
}
void Process_B(){
     //printf("proc B running\n");
     while(1){
         MsgEnv* envelope=rtx.receive_message();
         printf("proc B [%d] received msg envelope\n",ProcessB);
         printf("proc B [%d] sends msg envelope to C [%d]\n",ProcessB,ProcessC);
         rtx.send_message(ProcessC, envelope );         
     }
}
void Process_C(){
    //printf("proc C running\n");     
//    MsgEnv* msg;
//    PCB* proc_c=rtx.get_PCB(ProcessC);
//    int num;
//    while(1){
//        if(proc_c->msgQ->getsize()==0){
//            msg=rtx.receive_message();
//            printf("proc C [%d] received msg envelope\n",ProcessC);
//        }
//        else{            
//            msg=proc_c->msgQ->dequeue();
//            printf("proc C [%d] got msg from its msg_Q\n",ProcessC);
//        }
//        //if((ProcessC)->msgQ==NULL)
//        //        msg=rtx.receive_message();
//        num=msg->msg_data[1];
//        if(msg->type==count_report){
//        printf("proc C [%d] got count_report msg\n",ProcessC);
//            if(num%20==0){
//                printf("divisible by 20\n");
//                strcpy(msg->msg_data,"Process C\n");
//                rtx.send_console_chars(msg);
//                printf("console chars sent\n");
//                /*
//                 while(1){
//                    msg=rtx.receive_message();
//                    while(msg->type!=display_ack){msg=rtx.receive_message();};
//                    rtx.request_delay(1000,wakeup_code,msg);//go passive for 10 seconds
//                    if(msg->type==wakeup_code){break;}
//                    if((msg->type!=display_ack)||(msg->type!=wakeup_code))
//                        proc_c->msgQ->enqueue(msg);
//                }
//                 */
//                do{
//                    printf("C try to receive display_ack message\n");
//                    
//                    
//                    msg=rtx.receive_message();
//                    
//                }while(msg->type!=display_ack);
//                if(msg->type==display_ack){//go passive for 10 seconds
//                    rtx.request_delay(1000,wakeup_code,msg);   
//                }
//                do{
//                    msg=rtx.receive_message();
//                }while(msg->type!=wakeup_code);
//                if(msg->type==wakeup_code){
//                    break;
//                }                    
//                else{//if((msg->type!=display_ack)||(msg->type!=wakeup_code))
//                    proc_c->msgQ->enqueue(msg);            
//                }
//            }
//        }
//    rtx.release_msg_env(msg);
//    printf("proc C [%d] release msg because msg_data[1] not divisible by 20\n",ProcessC);
//    printf("proc C [%d] about to release processor and go back to ready queue\n",ProcessC);
//    rtx.release_processor();
//    } 
    
    //printf("proc C running\n");     
     MsgEnv* msg;
    PCB* proc_c=rtx.get_PCB(ProcessC);
    int num;
    while(1){
        if(proc_c->msgQ->getsize()==0){
            msg=rtx.receive_message();
            printf("proc C [%d] received msg envelope\n",ProcessC);
        }
        else{            
            msg=proc_c->msgQ->dequeue();
            printf("proc C [%d] got msg from its msg_Q\n",ProcessC);
        }
        //if((ProcessC)->msgQ==NULL)
        //        msg=rtx.receive_message();
        num=msg->msg_data[0];
        if(msg->type==count_report){
            printf("proc C [%d] got count_report msg\n",ProcessC);
            printf("count_report num is [%d]\n",num);
            if(num%20==0){
                printf("num is [%d] and is divisible by 20\n",num);
                strcpy(msg->msg_data,"#################<Process C>#################\n");
                
                rtx.send_console_chars(msg);
                printf("sent msg 'Process C' to console\n");
                /*
                 while(1){
                    msg=rtx.receive_message();
                    while(msg->type!=display_ack){msg=rtx.receive_message();};
                    rtx.request_delay(1000,wakeup_code,msg);//go passive for 10 seconds
                    if(msg->type==wakeup_code){break;}
                    if((msg->type!=display_ack)||(msg->type!=wakeup_code))
                        proc_c->msgQ->enqueue(msg);
                }
                 */
                printf("C first attempt to try to receive display_ack message\n");
                while(1){
                 //   printf("C in loop\n");
                    //printf("cur_proc before receive is {%d}\n",rtx.cur_proc->pid);
                    msg=rtx.receive_message();
                  //  printf("C received message ........\n");
                    //printf("C received  message, msg type is [%d]\n",msg->type);
                    if(msg->type==display_ack){
                        printf("proc C got display_ack msg!going passive for 10 sec\n");
                       //msg->sender_pid=ProcessC;                       
                        rtx.request_delay(10,wakeup_code,msg);   
                    }
                    else if(msg->type==wakeup_code){
                        printf("proc C got wakeup_code!\n");
                         break;
                    }
                    //printf("C does not want this msg now, so return it to MsgQ\n");
                    else{proc_c->msgQ->enqueue(msg);} 
                }
//                msg=rtx.receive_message();
//                while(msg->type!=display_ack);{
//                    
//                    msg=rtx.receive_message();
//                    printf("C try to receive display_ack message\n");
//                }
//                if(msg->type==display_ack){//go passive for 10 seconds
//                    rtx.request_delay(1000,wakeup_code,msg);   
//                }
//                do{
//                    msg=rtx.receive_message();
//                }while(msg->type!=wakeup_code);
//                if(msg->type==wakeup_code){
//                    break;
//                }                    
//                else{//if((msg->type!=display_ack)||(msg->type!=wakeup_code))
//                    proc_c->msgQ->enqueue(msg);            
//                }
            }
        };
    rtx.release_msg_env(msg);
    printf("proc C [%d] release msg because msg_data[1] not divisible by 20\n",ProcessC);
    printf("proc C [%d] about to release processor and go back to ready queue\n",ProcessC);
    rtx.release_processor();
    };      
    return;


}

void Clock_Process(){
//printf("Clock Process is running\n");	
        printf("in proc 6\n");
        MsgEnv* clockenv;
        int s,m,h;//seconds,minutes,hours
	    int time;
	    // char clk[MAXCHAR];
	    //convert system time to hh:mm:ss
    	
        while(1)
        {
        clockenv=rtx.receive_message();
        if(rtx.clock_display==1){
            usleep(1000000);
            time=rtx.get_time();
            s=time%60;
            m=((time-s)%3600)/60;
            h=(time-s-60*m)/3600;
            sprintf(clockenv->msg_data,"%i:%i:%i\n",h,m,s);
            printf("before send console chars\n");
            rtx.send_console_chars(clockenv);
            printf("after send console chars\n");
           // strcpy(msgenv->msg_data, h);
            //strcat(msgenv->msg_data,":");
            //strcat(msgenv->msg_data,m);
            //strcat(msgenv->msg_data,":");
            //strcat(msgenv->msg_data,s);
            //clk="%i:%i:%i\n",h,m,s;
            //strcpy(msgenv->msg_data,clk);
        	//int success=rtx.send_console_chars(msgenv);
        	//if (success==0)
            //   rtx.release_msg_env ( msgenv );
            //else
            //    printf("clock process send failed");
            }
         else rtx.release_processor();
         }
        return;
}

void Null_Process(){
    //printf("NULL porcess is running...\n"); 
    while(1) {rtx.release_processor();};
}
void cci_start(){//CCI input "s"
     MsgEnv* begin=rtx.request_msg_env();
     rtx.send_message(ProcessA,begin);
}
void cci_list_statuses(){//CCI input "ps"
     MsgEnv* envelope=rtx.request_msg_env();
     rtx.request_process_status(envelope);
     //printf("before send to console-->[%s]\n",envelope->msg_data);
     rtx.send_console_chars(envelope);
     while(1){
         envelope=rtx.receive_message();
         if(envelope->type==display_ack)
         {
             rtx.release_msg_env(envelope);
             return;
         }
         else{
             rtx.cur_proc->msgQ->enqueue(envelope);
         }         
     }        
}
void cci_set_wall_clock(int h, int m, int s){
     rtx.set_clock(h,m,s);
}
void cci_display_clock(){
    MsgEnv* clockenv=rtx.request_msg_env( );
    rtx.clock_display=1;
    rtx.send_message( Clock, clockenv );
}

void cci_stop_clock_display(){
     rtx.clock_display=0;
}
void cci_display_trace_buffers(){
     MsgEnv* message_envelope=rtx.request_msg_env();
     rtx.get_trace_buffers(message_envelope);
     int i;
     for(i=0;i<Max_Env_Data;i++){
             if (message_envelope->msg_data[i])
                printf("%i ",message_envelope->msg_data[i]);
             if ( (i+1)%4==0)
                printf("\n");
     }
}
void cci_terminate_RTX(){
rtx.terminate();
}
void cci_change_priority(int priority, int pid){
    int result;
    printf("(cci_change_priority)pri=[%d],pid-[%d]\n",priority,pid);
    result=rtx.change_priority(priority,pid);
    if(result!=0){printf("Inccorrect new priority or pid\n");}    
    return;
}

void Command_interpreter(){
    printf("CCI is running...\n"); 
    //printf("in CCI the cur_porc should be 3, and it is [%d]\n",rtx.cur_proc->pid);
    while(1){        
         MsgEnv* command=rtx.request_msg_env();
         command->sender_pid=CCI;
         rtx.get_console_chars(command);
         //printf("got console charts...\n"); 
         while(1){
             printf("\nCCI is trying to receive message\n");
             command=rtx.receive_message();
             if (command!=NULL)//should change to msg type equal to something
             {
                 printf("CCI received message\n");
                 break;
             }
         }
         
         //if(command==NULL){    not needed, receive_message primitive takes care of this =)
         //   cur_proc->status=Blocked_On_Receive;
         //   rtx.blkq_enqueue(Blocked_On_Resource,cur_proc);
         //   process_switch();
         //}
         if (command->msg_data[0]=='s' && command->msg_data[1]=='\0'){//send message to Process A
             printf("command='s'...\n");
             cci_start();
         }           
         else if (command->msg_data[0]=='p' && command->msg_data[1]=='s'&& command->msg_data[2]=='\0'){
             printf("command='ps'...\n"); 
             cci_list_statuses();
         }           
         else if (command->msg_data[0]=='c'){
             if (command->msg_data[4]==':'&& command->msg_data[7]==':' && command->msg_data[10]=='\0'){
                 printf("command='c hh:mm:ss'...\n"); 
                 int h=atoi (&(command->msg_data[2]));//*10+atoi(&(command->msg_data[3]));
                 int m=atoi(&(command->msg_data[5]));//*10+atoi(&(command->msg_data[6]));
                 int s=atoi(&(command->msg_data[8]));//*10+atoi(&(command->msg_data[9]));
                 if(h<=24 && m<=60 && s<=60 && h+m+s<=142)
                    cci_set_wall_clock(h,m,s);
                    
                 else printf("Invalid time\n");
             }
             else if (command->msg_data[1]=='d' && command->msg_data[2]=='\0'){
                 printf("command='cd'...\n"); 
                  cci_display_clock();
             }
             else if (command->msg_data[1]=='t' && command->msg_data[2]=='\0'){
                 printf("command='ct'...\n");  
                 cci_stop_clock_display();     
             }
         }
         else if (command->msg_data[0]=='b' && command->msg_data[1]=='\0'){
             printf("command='b'...\n");  
             cci_display_trace_buffers();
         }            
         else if (command->msg_data[0]=='t' && command->msg_data[1]=='\0'){
             printf("command='t'...\n");  
             cci_terminate_RTX();
         }
         else if (command->msg_data[0]=='n' ){//&& command->msg_data[1]=='\0'
             printf("command=[%s].\n",command->msg_data);   
             //printf("command='n priority[%d] process_id[%d]'...\n",command->msg_data[2],command->msg_data[4]);          
             //int priority = (command->msg_data[2]) - '0';
              //int pid = (command->msg_data[4]) - '0';
             int priority=atoi (&(command->msg_data[2]));
             int pid=atoi (&(command->msg_data[4]));
                cci_change_priority(priority,pid);
                
         }
         else
         {printf("command is not valid, please type something else...\n");
         printf("u 2nd char typed is %d\n",command->msg_data[1]);
         }
            
         rtx.release_msg_env(command);
         //printf("CCI releases msg env...\n");
     }
    return;
}
// kbd_handler
// Called by signal SIGUSR1 from keyboard reader process

/*void kbd_handler(int signum)
{
	inputbuf command;	
	printf("\n signal from kbd is received\n");
	// copy input buffer
	if (in_mem_p->indata[0] != '\0')
	{
                            
     MsgEnv * newMsgEnv=new MsgEnv();
     //newMsgEnv->msg_data=
	    strcpy(newMsgEnv->msg_data,in_mem_p->indata); 
        rtx.send_message(ProcessP,newMsgEnv);
       // printf("keb input is %s \n:", newMsgEnv->msg_data);
	    // we should parse the input string and execute the command given,
	    //  but for now we just echo the input
	    // 
	  //  strcpy(command.indata,in_mem_p->indata);
	   // printf("Keyboard input was: %s\n",command.indata);
	    in_mem_p->ok_flag = 0;  // tell child that the buffer has been emptied
	    kill(out_pid,SIGUSR2);
	    
	}

}

void crt_echo(int signum)
{
     out_mem_p->ok_flag=0;
}

void process_P(){
    printf("proc P is running\n");
    int tWait = 500000;
    MsgEnv * env=NULL;

    while (1) {
        printf("\n proc p about to get chars from kbd\n");
        //int test=rtx->get_console_chars (env);
        //if (test==-1)
        //printf("\n no char\n");
        //printf("\n proc p got chars from kbd\n");
        //rtx->get_console_chars(env);
        env = rtx.receive_message();
        printf("\n proc p got chars from kbd\n");
        int i=0;
        while (env==NULL) {
            //if(i==0)printf("\n null env\n");
            //i=1;
            usleep(tWait);
            env = rtx.receive_message();
        }
        printf("Keyboard input was: %s\n",env->msg_data);
        printf("proc P received msg\n");
        //rtx->send_console_chars(env);
        strcpy(out_mem_p->indata,env->msg_data); 
        env = rtx->receive_message();
        while (env == NULL) {
             usleep (tWait);
        env = rtx->receive_message();
        }
    }
}*/
//**************************************************************************

int main()
{

	
	// catch signals so we can clean up everything before exitting
	// signals defined in /usr/include/signal.h
	// e.g. when we recieved an interrupt signal SIGINT, call die()
	sigset(SIGINT,die);		// catch kill signals 
	sigset(SIGBUS,die);		// catch bus errors
	sigset(SIGHUP,die);		
	sigset(SIGILL,die);		// illegal instruction
	sigset(SIGQUIT,die);
	sigset(SIGABRT,die);
	sigset(SIGTERM,die);
	sigset(SIGSEGV,die);	// catch segmentation faults
        
        

	// signal from keyboard reader is SIGUSR1 (user-defined signal)
	// When there is input from the keyboard, call the kbd_handler() routine
	sigset(SIGUSR1,kbd_handler);	
	sigset(SIGUSR2,crt_handler);
        sigset(SIGALRM,timer_handler);
        
        
         
         	
  /* Create a new mmap file for read/write access with permissions restricted
     to owner rwx access only */
  fid1 = open(sfilename1, O_RDWR | O_CREAT | O_EXCL, (mode_t) 0755 );
  if (fid1 < 0){
    printf("Bad Open of mmap file <%s>\n", sfilename1);
	exit(0);
  };
    fid2 = open(sfilename2, O_RDWR | O_CREAT | O_EXCL, (mode_t) 0755 );
  if (fid2 < 0){
    printf("Bad Open of mmap file <%s>\n", sfilename2);
	exit(0);
  };

  // make the file the same size as the buffer 
  status = ftruncate(fid1, bufsize ); 
  if (status){
      printf("Failed to ftruncate the file <%s>, status = %d\n", sfilename1, status );
      exit(0);
  }

  status = ftruncate(fid2, bufsize ); 
  if (status){
      printf("Failed to ftruncate the file <%s>, status = %d\n", sfilename2, status );
      exit(0);
  }
	// pass parent's process id and the file id to child
	char childarg1[20], childarg2[20]; // arguments to pass to child process(es)
	int mypid = getpid();			// get current process pid
    
    for(int i=0;i<=1;i++)
    {
	sprintf(childarg1, "%d", mypid); // convert to string to pass to child
	if(i==0)
       sprintf(childarg2, "%d", fid1);   // convert the file identifier
    else
       sprintf(childarg2, "%d", fid2); 

	// create the keyboard reader process
	// fork() creates a second process identical to the current process,
	// except that the "parent" process has in_pid = new process's ID,
	// while the new (child) process has in_pid = 0.
	// After fork(), we do execl() to start the actual child program.
	// (see the fork and execl man pages for more info)
    if(i==0){
	in_pid = fork();
	if (in_pid == 0)	// is this the child process ?
	{
		execl("./keyboard", "keyboard", childarg1, childarg2, (char *)0);
		// should never reach here
		fprintf(stderr,"demo: can't exec keyboard, errno %d\n",errno);
		cleanup();
		exit(1);
	};
    }
    if(i==1){
    out_pid=fork();
	if (out_pid == 0)	// is this the child process ?
	{
		execl("./crt", "crt", childarg1, childarg2, (char *)0);
		// should never reach here
		fprintf(stderr,"demo: can't exec CRT, errno %d\n",errno);
		cleanup();
		exit(1);
	};
    }
	// the parent process continues executing here

	// sleep for a second to give the child process time to start
	sleep(1);

	// allocate a shared memory region using mmap 
	// the child process also uses this region
	
    mmap_ptr1 = mmap((void*) 0,   /* Memory location, 0 lets O/S choose */
		    bufsize,              /* How many bytes to mmap */
		    PROT_READ | PROT_WRITE, /* Read and write permissions */
		    MAP_SHARED,    /* Accessible by another process */
		    fid1,           /* the file associated with mmap */
		    (off_t) 0);    /* Offset within a page frame */
    if (mmap_ptr1 == MAP_FAILED){
      printf("Parent's memory map has failed, about to quit!\n");
	  die(0);  // do cleanup and terminate
    };
	
    mmap_ptr2 = mmap((void*) 0,   /* Memory location, 0 lets O/S choose */
		    bufsize,              /* How many bytes to mmap */
		    PROT_READ | PROT_WRITE, /* Read and write permissions */
		    MAP_SHARED,    /* Accessible by another process */
		    fid2,           /* the file associated with mmap */
		    (off_t) 0);    /* Offset within a page frame */
    if (mmap_ptr2 == MAP_FAILED){
      printf("Parent's memory map has failed, about to quit!\n");
	  die(0);  // do cleanup and terminate
    };
    
	if (i==0)
	in_mem_p = (inputbuf *) mmap_ptr1;   // pointer to shared memory
	else 
	out_mem_p = (inputbuf *) mmap_ptr2;
	  // we can now use 'in_mem_p' as a standard C pointer to access 
	  // the created shared memory segment 
	
    }
	
    ualarm(1000000,1000000);
    /*RTX INITIALIZATION*/
    initTable init_table[Num_Proc];
    init_table [0].pid = ProcessA;
    init_table [0].priority = 2;
    init_table [0].status = Ready;
    init_table [0].start_address = &Process_A;
    init_table [1].pid = ProcessB;
    init_table [1].priority = 2;
    init_table [1].status = Ready;
    init_table [1].start_address = &Process_B;
    init_table [2].pid = ProcessC;
    init_table [2].priority = 2;
    init_table [2].status = Ready;
    init_table [2].start_address = &Process_C;
    init_table [3].pid = CCI;
    init_table [3].priority = 0;
    init_table [3].status = Ready;
    init_table [3].start_address = &Command_interpreter;
    init_table [4].pid = KB;
    init_table [4].priority = I_Process;//not in ready queue
    init_table [4].status = I_Process;
    init_table [4].start_address = &kbd_iproc;
    init_table [5].pid = CRT;
    init_table [5].priority = I_Process;//not in ready queue
    init_table [5].status = I_Process;
    init_table [5].start_address = &crt_iproc;
    init_table [6].pid = Clock;
    init_table [6].priority = 2;
    init_table [6].status = Ready;
    init_table [6].start_address = &Clock_Process;
    init_table [7].pid = Timer;
    init_table [7].priority = I_Process;
    init_table [7].status = I_Process;
    init_table [7].start_address = &timer_iproc;
    init_table [8].pid = NullProcess;
    init_table [8].priority = 3;
    init_table [8].status = Ready;
    init_table [8].start_address = &Null_Process;
    printf("table created\n");
    rtx.initialization(init_table);
        printf("initialization done\n");    

        
        
	// now start doing whatever work you are supposed to do
	// in this case, do nothing; only the keyboard handler will do work
	in_mem_p->ok_flag = 0;
	printf("\nType something followed by end-of-line and it will be echoed\n\n");
	//process_P();
	while (1);

	// should never reach here, but in case we do, clean up after ourselves
	cleanup();
	exit(1);
} // main
